抛出和捕捉

  提供异常这个概念就是为了帮助处理错误的报告。例如,

    struct Range_error {
        int i;
        Range_error(int ii) { i = ii; }        // 构造函数(2.5.2节、10.2.3节)
    };

    char to_char(int i)
    {
        if(i < numeric_limits<char>::min || numeric_limits<char>::max < i) // 參看22.2节
            throw Range_error(i);
        return i;
    }

函数to_char()或者返回具有数值i的char,或者抛出一个Range_error。这里的基本想法是,如果函数发现了一个自己无法处理的问题,它就抛出(throw)一个异常,希望它的(直接或间接)调用者能够处理这个问题。如果一个函数想处理某个问题,它就可以说明自己要捕捉(catch)用于报告该种问题的异常。例如,如果想调用to_char()并捕捉它可能抛出的异常,我们可以写

    void g(int i)
    {
        try {
            char c = to_char(i);
            // ...
        }
        catch(Range_error) {
            cerr << "oops\n";
        }
    }

程序结构

    catch (/* ... */) {
        // ...
    }

称为一个异常处理器,它的使用只能紧接着try关键字作为前缀的块之后,或者紧接着另一个异常处理器之后。catch也是一个关键字。在括号里包含着一个声明,其使用方式类似于函数参数的声明。也就是说,该声明描述的是这个处理器要捕捉的对象的类型,并可以为所捕捉的对象命名。举个例子,如果我们想知道抛出的Range_error的值,我们就可以为catch的参数提供一个名字,就像为函数的参数命名一样。例如写:

    void h(int i)
    {
        try {
            char c = to_char(i);
            // ...
        }
        catch (Range_error x) {
            cerr << "oops: to_char(" << x.i << "\n)";
        }
    }

如果在一个try块里的任何代码---或者由那里调用的东西---抛出了一个异常,那就会逐个检查这个try块后面的处理器。如果所抛出的异常属于某个处理器所描述的类型,这个处理器就会被执行。如果try块未抛出异常,这些异常处理器都将被忽略,使该try块的活动方式就像是普通的块。如果抛出了一个异常,而又没有try块捕捉它,整个程序就将终止(14.7节)。

  简而言之,C++异常处理是一种从一个函数里将控制传递到有意确定的一些代码的方式。如果需要,也可以同时把有关错误的某些信息传递给调用者。C程序员可以将异常处理想象为一种用于取代setjmp/longjmp(16.1.2节)的、具有良好行为方式的机制。在异常处理与类之间重要的相互作用将在第14章讨论。

🔚